package org.agony2d.gpu.core {
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;
	import org.agony2d.gpu.supportClasses.ContainerAABase;
	import org.agony2d.gpu.supportClasses.LayerAABase;
	
	import org.agony2d.Agony;
	import org.agony2d.core.agony_internal;
	import org.agony2d.debug.Logger;
	import org.agony2d.gpu.FusionAA;
	import org.agony2d.gpu.StateGroupAA;
	import org.agony2d.input.ATouchEvent;
	import org.agony2d.input.Touch;
	import org.agony2d.input.TouchManager;
	import org.agony2d.notify.AEvent;
	
	use namespace agony_internal;
	
	/** [ WorldAA ]
	 *  [◆]
	 *  	1.  numLayers
	 *  [◆◆]
	 *  	1.  reset
	 *  	2.  exit
	 * 
	 *  	3.  createLayer
	 *  	4.  getLayerAt
	 */
public class WorldAA extends ContainerAABase {
	
	public function WorldAA( width:int, height:int, invalidWhenLeave:Boolean ) {
		m_worldWidth = width < 0 ? g_fullWidth : width
		m_worldHeight = height < 0 ? g_fullHeight : height
		m_invalidWhenLeave = invalidWhenLeave
		
		
		
		
		if(!g_txt){
			g_txt = new TextField
			g_txt.y = 15
			g_txt.x = 190
			g_txt.text = "0"
			g_txt.autoSize = TextFieldAutoSize.LEFT
			Agony.stage.addChild(g_txt)
		}
	}
	
	public function get numLayers() : int {
		return m_numLayers
	}
	
	public function get currTouch() : Touch {
		return m_currTouch
	}
	
	public function get width() : int {
		return m_worldWidth
	}
	
	public function get height() : int {
		return m_worldHeight
	}
	
	public function reset() : void {
		var i:int
		
		while (i < m_numLayers) {
			m_layerList[i++].reset()
		}
	}
	
	public function exit() : void {
		var i:int
		
		while (i < m_numLayers) {
			m_layerList[i++].stop()
		}
	}
	
	public function createLayer( stateAARef:Class ) : StateGroupAA {
		var layer:LayerAABase
		
		m_layerList[m_numLayers++] = layer = new LayerAABase(stateAARef)
		layer.m_world = this
		layer.m_parent = this
		return layer
	}
	
	public function getLayerAt( index:int ) : StateGroupAA {
		return m_layerList[index]
	}
	
	override public function kill() : void {
		AAManager.removeWorld(this)
		this.dispose()
	}
	
	override public function set pivotX( v:Number ) : void {
		Logger.reportError(this, "pivotX", "non useful...!!")
	}
	
	override public function set pivotY( v:Number ) : void {
		Logger.reportError(this, "pivotY", "non useful...!!")
	}
	
	override public function set rotation( v:Number ) : void {
		Logger.reportError(this, "rotation", "non useful...!!")
	}
	
	override public function set scaleX( v:Number ) : void {
		Logger.reportError(this, "scaleX", "non useful...!!")
	}
	
	override public function set scaleY( v:Number ) : void {
		Logger.reportError(this, "scaleY", "non useful...!!")
	}
	
	override public function setCollisionMethod( v:Function ) : void {
		Logger.reportError(this, "setCollisionMethod", "non useful...!!")
	}
	
	override public function globalToLocal( globalX:Number, globalY:Number, result:Point = null ) : Point {
		if (!result) {
			result = new Point
		}
		result.setTo(globalX, globalY)
		return result	
	}
	
	override public function localToGlobal( localX:Number, localY:Number, result:Point = null ) : Point {
		if (!result) {
			result = new Point
		}
		result.setTo(localX, localY)
		return result	
	}
	
	override public function collide( x:Number, y:Number, global:Boolean = true ) : Boolean {
		return this.checkCollisionNode(x, y, false)
	}
	
	
	
	agony_internal static var g_scissorRect:Rectangle = new Rectangle
	
	agony_internal var m_layerList:Array = []
	agony_internal var m_numLayers:int
	agony_internal var m_worldWidth:int
	agony_internal var m_worldHeight:int
	agony_internal var m_currTouch:Touch
	agony_internal var m_touchMap:Dictionary = new Dictionary // Touch:PixelsAA
	agony_internal var m_invalidWhenLeave:Boolean
	
	
	
	final override agony_internal function dispose() : void {
		var i:int
		
		this.removeAllListeners()
		while (i < m_numLayers) {
			m_layerList[i++].dispose()
		}
	}
	
	override agony_internal function attach( parent:NodeAA ) : void {
		Logger.reportError(this, "attach", "non useful...!!")
	}
	
	override agony_internal function removeNode( node:NodeAA ) : void {
		var index:int
		
		index = m_layerList.indexOf(node)
		m_layerList.splice(index, 1)
		--m_numLayers
	}
	
	[Inline]
	final override agony_internal function checkCollisionNode( globalX:Number, globalY:Number, forInteract:Boolean ) : NodeAA {
		var layer:GroupAA
		var node:NodeAA
		var l:int
		
		if (forInteract && m_intouchable) {
			return null
		}
		l = m_numLayers
		while (--l > -1) {
			layer = m_layerList[l]
			node = layer.checkCollisionNode(globalX, globalY, forInteract)
			if (node) {
				return node
			}
		}
		return null
	}
	
	override agony_internal function render( vertexChanged:Boolean ) : void {
		var i:int
		var layer:GroupAA
		var scissorEnabled:Boolean
		
		//trace("+++++++++++++++++++++++++++++")
		
		scissorEnabled = m_x != 0 || m_y != 0 || m_worldWidth != g_fullWidth || m_worldHeight != g_fullHeight
		if (scissorEnabled) {
			g_scissorRect.setTo(m_x, m_y, m_worldWidth, m_worldHeight)
			AAManager.g_context3d.setScissorRectangle(g_scissorRect)
		}
		if (m_altered) {
			this.doUpdateDownward()
			m_altered = false
			vertexChanged = true
		}	
		
		while (i < m_numLayers) {
			g_t = getTimer()
			m_layerList[i].render(vertexChanged)
			g_time = getTimer() - g_t
			g_txtList[i] += g_time
			i++
			
			//trace(g_time)
		}
		
		
		
		if (++g_count >= 30) {
			i = 0
			var str:String = ""
			while(i < m_numLayers){
				str += (g_txtList[i++]/ g_count).toFixed(2) + " | "
			}
			g_txt.text = str
			g_txtList[0] = g_txtList[1] =g_txtList[2] =g_txtList[3] =g_txtList[4] = g_time = g_timeA = g_count = 0
			
		}
		if (scissorEnabled) {
			AAManager.g_context3d.setScissorRectangle(null)
		}
	}
	
	
	agony_internal var g_txtList:Array = [0,0,0,0,0]
	agony_internal var g_txt:TextField
	agony_internal var g_time:int
	agony_internal var g_timeA:int
	agony_internal var g_count:int
	agony_internal var g_t:int
	
	
	
	agony_internal function handleInteract( touch:Touch, type:String ) : void {
		var pxA:PixelsAA, pxB:PixelsAA, pxH:PixelsAA
		var group:GroupAA
		var node:NodeAA
		var l:int
		var outOfBounds:Boolean
		var globalX:Number, globalY:Number
		
		globalX = touch.m_stageX
		globalY = touch.m_stageY
		outOfBounds = globalX < m_x || globalX > m_x + m_worldWidth || globalY < m_y || globalY > m_y + m_worldHeight
		pxB = m_touchMap[touch]
		m_currTouch = touch
		if (pxB || type == ATouchEvent.NEW_TOUCH) {
			pxA = this.checkCollisionNode(globalX, globalY, true) as PixelsAA
			if (pxA) {
				if (type == ATouchEvent.NEW_TOUCH) {
					if (!pxA.m_bindingTouch && !outOfBounds) {
						m_touchMap[touch] = pxA.m_bindingHoverNode = pxA
						pxA.m_bindingTouch = touch
						pxA.bubble(AEvent.PRESS, true)
						//trace(AEvent.PRESS)
						return
					}
				}
				else if (type == AEvent.RELEASE) {
					if (pxA == pxB && !TouchManager.g_allInvalid && !outOfBounds) {
						pxA.bubble(AEvent.CLICK, false)
					}
					else if (!pxA.m_bindingTouch && !outOfBounds) {
						pxA.bubble(type, false)
					}
					pxB.bubble(type, true)
					delete m_touchMap[touch]
					pxB.m_bindingTouch = null
					pxB.m_bindingHoverNode = null
					//trace(AEvent.RELEASE)
					return
				}
				else if (type == AEvent.MOVE) {
					pxH = pxB.m_bindingHoverNode
					if (!outOfBounds) {
						pxA.bubble(type, true)
					}
					if (pxA != pxH) {
						if ((pxA == pxB || pxA.m_bindingTouch) && !outOfBounds) {
							pxB.m_bindingHoverNode = pxA
							pxA.bubble(AEvent.OVER, false)
						}
						if (pxH) {
							if (pxH == pxB || pxH.m_bindingTouch) {
								pxH.bubble(AEvent.LEAVE, false)
							}
							if (m_invalidWhenLeave && pxA != pxB) {
								delete m_touchMap[touch]
								pxB.m_bindingTouch = null
								pxB.m_bindingHoverNode = null
							}
						}
					}
					//trace(AEvent.MOVE)
					return
				}
			}
		}
		if (type == AEvent.MOVE && pxB) {
			pxH = pxB.m_bindingHoverNode
			if (pxH) {
				if (pxH == pxB || pxH.m_bindingTouch) {
					pxH.bubble(AEvent.LEAVE, false)
				}
				pxB.m_bindingHoverNode = null
				if (m_invalidWhenLeave) {
					delete m_touchMap[touch]
					pxB.m_bindingTouch = null
				}
			}
		}
		else if (type == AEvent.RELEASE) {
			if (pxB) {
				pxB.bubble(type, false)
				delete m_touchMap[touch]
				pxB.m_bindingTouch = null
				pxB.m_bindingHoverNode = null
				//trace(AEvent.RELEASE)
			}
		}
		else if (type == ATouchEvent.NEW_TOUCH) {
			type = AEvent.PRESS
		}
		if (!outOfBounds) {
			this.dispatchDirectEvent(type)
			//trace(type)
		}
		m_currTouch = null
	}

}
}